package com.jgzj.example.export.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.*;

/**
 * @description: 获取 @Export 标记的内容，封装Map
 * @author: 子木
 * @since: 2021/05/16
 */
@Component
@Slf4j
public class ExportListenerProcessor implements BeanPostProcessor {

    private final Map<String, QueryMethodInfo> map = new HashMap<>();

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    /**
     * 执行时机：创建每一个Bean的后置处理时
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        try {
            final Method[] methods = ReflectionUtils.getAllDeclaredMethods(bean.getClass());
            if (methods != null) {
                for (Method method : methods) {
                    final Export export = AnnotationUtils.findAnnotation(method, Export.class);
                    if (null != export && !Objects.isNull(export)) {
                        this.initQueryMethodInfo(bean,method,export);
                    }
                }
            }
        } catch (Exception e) {
            log.error("Error init query method info ! Please check @Export");
        }
        return bean;
    }

    private void initQueryMethodInfo(Object bean, Method method, Export export) {
        QueryMethodInfo queryMethodInfo = new QueryMethodInfo();
        queryMethodInfo.setModelClass(export.model());
        queryMethodInfo.setClazz(bean.getClass());
        queryMethodInfo.setMethod(method);
        queryMethodInfo.setParameterType(method.getParameterTypes()[0]);
        queryMethodInfo.setExportFormat(export.exportFormat());
        queryMethodInfo.setReturnType(method.getReturnType());
        if (export.columnNames().length() > 0) {
            List<String> columns = Arrays.asList(export.columnNames().split(","));
            List<List<String>> result = new ArrayList<>();
            columns.stream().forEach(column -> {
                List<String> rows = new ArrayList<>();
                Arrays.asList(column.split(":")).stream().forEach(row -> {
                    rows.add(row);
                });
                result.add(rows);
            });
            queryMethodInfo.setColumnNames(result);
        }
        if (export.includeFields().length > 0) {
            queryMethodInfo.setIncludeColumnNames(new HashSet<String>(Arrays.asList(export.includeFields())));
        }
        if (export.excludeFields().length > 0) {
            queryMethodInfo.setExcludeColumnNames(new HashSet<String>(Arrays.asList(export.excludeFields())));
        }
        this.map.put(export.value(), queryMethodInfo);
    }

    public Map<String, QueryMethodInfo> getMap() {
        return this.map;
    }
}